﻿using System.Data.Entity;
using InvestmentIntelligence.Data.Repository.EFImplementation;
using InvestmentIntelligence.DB;
using InvestmentIntelligence.DbModel.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity.Core.Objects;
using System.Linq;
using InvestmentIntelligence.Logging.Client.Models;

namespace InvestmentIntelligence.Data.Repository.SqlImplementation
{
    public class LogEntryRepository : IIPRepository<LogEntry>, ISqlLogEntryRepository
    {
        public LogEntry Get(int type, string identity)
        {
            var typeId = (short)type;
            return Get(v => v.TypeId == typeId && v.Identity == identity);
        }

        public LogEntry Get(int type, DateTime date)
        {
            var typeId = (short)type;
            return GetList(x => x.Where(v => v.TypeId == typeId && DbFunctions.TruncateTime(v.Date) == date.Date)).LastOrDefault();
        }

        public void DeleteObsoleteLogs(int type)
        {
            //ToDo: Implement external process to delete obsolete ADBCalculation logs (because it takes too much time)
            using (var dc = new DataConnection())
            {
                string sql;
                if (type == (int)LogEntryType.AdbCalculationInfo)
                {
                    sql = @"
DELETE del
FROM Reports.LogEntry del
LEFT JOIN 
(
	SELECT le.Id 
	FROM Reports.LogEntry le
	INNER JOIN Analytics.Investment inv on le.[Identity] = cast(inv.Id as nvarchar)	    
) stay on stay.Id = del.Id
WHERE del.TypeId = @TypeId and stay.Id is null
";
                }
                else
                {
                    sql = @"
DELETE FROM Reports.LogEntry
WHERE [TypeId] = @TypeId";
                }

                dc.Timeout = 60 * 30; //30 min
                dc.Parameters.AddWithValue("@TypeId", type);
                dc.Execute(sql, CommandType.Text);
            }
        }

        public new void Merge(IEnumerable<LogEntry> items)
        {
            var identitiesClause = string.Join(",", items.Select(i => String.Format("'{0}'", i.Identity)));
            using (var dc = new DataConnection())
            {
                dc.Begin();
                
                var tempTable = CreateTempTable(dc);
                dc.BulkCopy(tempTable, items);

                Update(dc, tempTable, identitiesClause);
                Insert(dc, tempTable, identitiesClause);

                dc.Commit();
            }
        }

        private static string CreateTempTable(DataConnection dc)
        {
            var name = "##LogEntry" + Guid.NewGuid().ToString().Replace("-", "");
            dc.Execute(string.Format("SELECT * INTO {0} FROM [Reports].[LogEntry] WHERE 1=2", name), CommandType.Text);
            return name;
        }

        private static void Update(DataConnection dc, string tempTable, string identitiesClause)
        {
            var sql = string.Format(@"
UPDATE le 
SET
    le.[Date] = t.[Date],
    le.[Data] = t.[Data],
    le.[StateId] = 1
FROM Reports.LogEntry as le
JOIN {0} as t ON le.TypeId = t.TypeId
    and le.[Identity] = t.[Identity]
    and le.[Identity] IN ({1})", tempTable, identitiesClause);

            dc.Execute(sql, CommandType.Text);
        }

        private static void Insert(DataConnection dc, string tempTable, string identitiesClause)
        {
            var sql = string.Format(@"
INSERT INTO Reports.LogEntry ([Date],[Data],[Identity],[StateId],[TypeId])
SELECT t.[Date], t.[Data], t.[Identity], t.[StateId], t.[TypeId]
FROM {0} as t
LEFT JOIN Reports.LogEntry as le ON le.TypeId = t.TypeId
    and le.[Identity] = t.[Identity]
    and le.[Identity] IN ({1})
WHERE le.Id is NULL", tempTable, identitiesClause);

            dc.Execute(sql, CommandType.Text);
        }
    }
}
